//
//  VideoPlayerManager.m
//  BeautyCircle
//
//  Created by xiao_kl on 16/10/20.
//  Copyright © 2016年 MissApp. All rights reserved.
//

#import "VCVideoPlayerManager.h"
#import "VCInformationTool.h"

@interface VCVideoPlayerManager ()

/* 播放器 */
@property (nonatomic,strong) AVPlayer *moviePlay;

/** 判断是否是人为暂停*/
@property (nonatomic,assign)BOOL isArtificialPause;

/** 播放源*/
@property (nonatomic ,strong) AVPlayerItem *item;
@end

@implementation VCVideoPlayerManager

/** 播放单利*/
+(instancetype)PlayManager{
    static VCVideoPlayerManager *palymanager ;
    if (palymanager == nil) {
        palymanager = [[VCVideoPlayerManager alloc] init];
        
//#pragma clang diagnostic push
//#pragma clang diagnostic ignored "-Wdeprecated-declarations"
//        //监听输出设备变化
//        AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, audioRouteChangeListenerCallback, (__bridge void*)palymanager);
//
//#pragma clang diagnostic pop
    }
    return palymanager;
}
- (instancetype)init
{
    self = [super init];
    if (self) {
        self.moviePlay = [[AVPlayer alloc] init];
        self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.moviePlay];
        
    }
    return self;
}

-(void)dealloc{
    [self removeVideoKVO];
    [self removeVideoNotic];
}
#pragma mark - **************** get方法
 /** get方法*/
-(NSTimeInterval)duration{
    NSTimeInterval result     = CMTimeGetSeconds(self.moviePlay.currentItem.duration);
    if (isnan(result)) result = 0;
    return result;
}
-(NSTimeInterval)currentPlaybackTime{
    NSTimeInterval result     = CMTimeGetSeconds(self.moviePlay.currentItem.currentTime);
    if (isnan(result)|| [VCInformationTool getPlayerIsChangeTime]) result = 0;
    return result;
}

/**
 *  计算缓冲时长
 */
-(NSTimeInterval)bufferingProgress{
    NSArray *loadedTimeRanges = [[self.moviePlay currentItem] loadedTimeRanges];
    CMTimeRange timeRange     = [loadedTimeRanges.firstObject CMTimeRangeValue];// 获取缓冲区域
    float startSeconds        = CMTimeGetSeconds(timeRange.start);
    float durationSeconds     = CMTimeGetSeconds(timeRange.duration);
    NSTimeInterval result     = startSeconds + durationSeconds;// 计算缓冲总进度
    if (isnan(result) || [VCInformationTool getPlayerIsChangeTime]) result = 0;
    return result;
}
#pragma mark - **************** set方法
-(void)setCurrentProgress:(NSTimeInterval)currentProgress{
    _currentProgress = currentProgress;
    
     /** 设置时间*/
//    NSTimeInterval currentTime = CMTimeGetSeconds(self.moviePlay.currentItem.duration) * currentProgress;
    [self.moviePlay.currentItem seekToTime:CMTimeMakeWithSeconds(currentProgress, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
}

-(void)setContentURL:(NSURL *)contentURL{
    _contentURL = contentURL;
    
    if (contentURL == nil) {
        return;
    }
    //通知:
    [self removeVideoKVO];
    [self removeVideoNotic];
    
    [self.moviePlay replaceCurrentItemWithPlayerItem:nil];
    self.item = nil;
    self.item = [AVPlayerItem playerItemWithURL:contentURL];
//    self.item.preferredForwardBufferDuration = 30;
    self.item.canUseNetworkResourcesForLiveStreamingWhilePaused = YES;
    
    
    [self.moviePlay replaceCurrentItemWithPlayerItem:self.item];
//    self.moviePlay = [AVPlayer playerWithPlayerItem:self.item];
    
//    [self.moviePlay play];
    [self addVideoNotic];
    [self addVideoKVO];
}

-(BOOL)isPlaybackLikelyToKeepUp{
    return self.item.isPlaybackLikelyToKeepUp;
}
#pragma mark - KVO
- (void)addVideoKVO
{
    //KVO
    [self.item addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];//播放状态
    [self.item addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];//监听播放器的下载进度
    [self.item addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];//播放缓冲区为空
    [self.item addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
    



}
//#pragma mark - 在用户插入和拔出耳机时，有可能也会导致视频暂停。监听
////如果是输出设备发生变化，我们如果要继续播放视频的话，我们只需监听到设备变化时调用play就好了.
//void audioRouteChangeListenerCallback (
//                                       void                      *inUserData,
//                                       AudioSessionPropertyID    inPropertyID,
//                                       UInt32                    inPropertyValueS,
//                                       const void                *inPropertyValue
//                                       ) {
//#pragma clang diagnostic push
//#pragma clang diagnostic ignored "-Wdeprecated-declarations"
//    UInt32 propertySize = sizeof(CFStringRef);
//    AudioSessionInitialize(NULL, NULL, NULL, NULL);
//    CFStringRef state = nil;
//
//    //获取音频路线
//    AudioSessionGetProperty(kAudioSessionProperty_AudioRoute
//                            ,&propertySize,&state);//kAudioSessionProperty_AudioRoute：音频路线
//    NSLog(@"%@",(NSString *)CFBridgingRelease(state));//Headphone 耳机  Speaker 喇叭.
//    if (![VCVideoPlayerManager PlayManager].isArtificialPause) {
//        [[VCVideoPlayerManager PlayManager] play];
//    }
//#pragma clang diagnostic pop
//}
- (void)removeVideoKVO {
    [self.item removeObserver:self forKeyPath:@"status"];
    [self.item removeObserver:self forKeyPath:@"loadedTimeRanges"];
    [self.item removeObserver:self forKeyPath:@"playbackBufferEmpty"];
    [self.item removeObserver:self forKeyPath:@"playbackLikelyToKeepUp"];
}
/**
 *  监听属性值发生改变时回调
 */
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"status"]) {//播放状态
        NSLog(@"------status%@ ",change);
        if ([[change valueForKey:NSKeyValueChangeNewKey] intValue] == AVPlayerItemStatusUnknown) {//播放播放未知状态
            NSLog(@"播放器状态 未知状态 value = %ld",(long)AVPlayerItemStatusUnknown);
            if ([self.delegate respondsToSelector:@selector(loding)]) {//正在加载
                [self.delegate loding];
            }
        }else if ([[change valueForKey:NSKeyValueChangeNewKey] intValue] == AVPlayerItemStatusReadyToPlay){//播放
            NSLog(@"播放器状态 播放开始 value = %ld",(long)AVPlayerItemStatusReadyToPlay);
            NSLog(@"------status%@",change);
            if ([self.delegate respondsToSelector:@selector(playing)]) {//播放
                [self.delegate playing];
            }
        }else{//播放错误
            NSLog(@"播放器状态 播放错误 value = %ld",(long)AVPlayerItemStatusFailed);
            [self performSelector:@selector(logError) withObject:nil afterDelay:0.5];
            if ([self.delegate respondsToSelector:@selector(linkPlaybackailedWithError:)]) {//链接播放失败
                [self.delegate linkPlaybackailedWithError:self.moviePlay.error];
            }
        }
        
    }else if ([keyPath isEqualToString:@"loadedTimeRanges"]){//加载时间范围
//        NSLog(@"加载时间范围");
    }else if ([keyPath isEqualToString:@"playbackBufferEmpty"]){
        NSLog(@"缓冲不足暂停了--%i",self.item.isPlaybackBufferEmpty);
        
        if ([self.delegate respondsToSelector:@selector(loding)]) {
            [self.delegate loding];
        }
            
        

    } else if ([keyPath isEqualToString:@"playbackLikelyToKeepUp"]) {
        
        
        //由于 AVPlayer 缓存不足就会自动暂停，所以缓存充足了需要手动播放，才能继续播放
        
        if ([self.delegate respondsToSelector:@selector(playing)]) {
            [self.delegate playing];
        }

        
    }else{
        NSLog(@"播放状态%@",keyPath);
    }
    
}
-(void)logError{
    NSLog(@"error = %@",self.moviePlay.error);
    NSLog(@"error = %@",self.moviePlay.error.description);
    NSLog(@"error = %@",self.item.error);
    NSLog(@"error = %@",self.item.errorLog);
    
}
/**
 *  添加通知监控媒体播放控制器状态
 */
#pragma mark - Notic
- (void)addVideoNotic {

    //Notification
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(movieToEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];//播放到结束时间通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(movieJumped:) name:AVPlayerItemTimeJumpedNotification object:nil];//时间已跳过通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(movieStalle:) name:AVPlayerItemPlaybackStalledNotification object:nil];//播放停止通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(FailedToPlayToEnd:) name:AVPlayerItemFailedToPlayToEndTimeNotification object:nil];//播放失败
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ErrorLogEntryNotification:) name:AVPlayerItemNewErrorLogEntryNotification object:nil];//播放错误log
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backGroundPauseMoive) name:NSExtensionHostDidEnterBackgroundNotification object:nil];//应用程序进入了后台通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ForegroundGroundPlayMoive) name:NSExtensionHostWillEnterForegroundNotification object:nil];//应用程序进入了前台通知
    // 监听耳机插入和拔掉通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:) name:AVAudioSessionRouteChangeNotification object:nil];
}
- (void)removeVideoNotic {
    
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemPlaybackStalledNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemTimeJumpedNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

/**播放错误log*/
-(void)ErrorLogEntryNotification:(NSNotification *)notic {
    NSLog(@"播放错误log-------------~~~");
}
/**播放失败*/
-(void)FailedToPlayToEnd:(NSNotification *)notic {
    
    NSLog(@"播放失败-------------~~~%@",notic.userInfo);
    if ([self.delegate respondsToSelector:@selector(playbackailed)]) {
        [self.delegate playbackailed];
    }
}
 /** 播放到结束时间通知*/
- (void)movieToEnd:(NSNotification *)notic {
    NSLog(@"播放到结束时间通知~~~");
    if ([self.delegate respondsToSelector:@selector(endPlay)]) {//正在加载
        [self.delegate endPlay];
    }
    
}

/** 时间已跳过通知*/
- (void)movieJumped:(NSNotification *)notic {
    
}
 /** 播放停止通知*/
- (void)movieStalle:(NSNotification *)notic {
    NSLog(@"缓存不足的时候回停止=====什么时候停止播放啊~~~");
}
 /** 应用程序进入了后台通知*/
- (void)backGroundPauseMoive {
    [self pause];
    if ([self.delegate respondsToSelector:@selector(AppEnterBackground)]) {//正在加载
        [self.delegate AppEnterBackground];
    }
}
 /** 应用程序进入了前台通知*/
- (void)ForegroundGroundPlayMoive {
    if ([self.delegate respondsToSelector:@selector(AppEnterForeground)]) {//播放
        [self.delegate AppEnterForeground];
    }

}
/**
 *  耳机插入、拔出事件
 */
- (void)audioRouteChangeListenerCallback:(NSNotification*)notification {
    NSDictionary *interuptionDict = notification.userInfo;
    
    NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
    
    switch (routeChangeReason) {
            
        case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
            // 耳机插入
            if (!self.isArtificialPause) {
                [self play];
            }
            break;
            
        case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: {
            // 耳机拔掉
            // 拔掉耳机继续播放
            if (!self.isArtificialPause) {
                [self play];
            }
        }
            break;
            
        case AVAudioSessionRouteChangeReasonCategoryChange:
            // called at start - also when other audio wants to play
            NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange");
            break;
    }
}

/** 暂停方法*/
-(void)pause{
    self.isArtificialPause = YES;
    [self.moviePlay pause];
}
/** 播放方法*/
-(void)play{
    self.isArtificialPause = NO;
    [self.moviePlay play];
}
/** 停止*/
-(void)stop{
    NSLog(@"调用我就会停止播放吗???");
    [self.moviePlay pause];
    [self.moviePlay setRate:0];
    [self.moviePlay replaceCurrentItemWithPlayerItem:nil];
    //通知:
    [self removeVideoKVO];
    [self removeVideoNotic];
    [self.moviePlay replaceCurrentItemWithPlayerItem:nil];
    self.item = nil;
    self.contentURL = nil;
}

@end
